package cloud.hedou.abp.auth

import cloud.hedou.abp.starter.Auth
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.core.GrantedAuthorityDefaults
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.config.web.servlet.invoke
import org.springframework.security.oauth2.jwt.JwtDecoder
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.access.AccessDeniedHandler

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
class AbpSecurityConfiguration : WebSecurityConfigurerAdapter() {

    private val logger = LoggerFactory.getLogger(AbpSecurityConfiguration::class.java)

    @Autowired
    private lateinit var auth: Auth

    @Autowired
    private lateinit var apbJwtDecoder: JwtDecoder

    @Autowired
    private lateinit var abpBearerTokenResolver: BearerTokenResolver

    /** 注入权限前缀 */
    @get:Bean
    val grantedAuthorityDefaults: GrantedAuthorityDefaults
        get() = GrantedAuthorityDefaults("")

    /** 从JWT中提取用户权限的转换器 */
    @Bean
    fun jwtAuthenticationConverter(converter: AbpGrantedAuthoritiesConverter): JwtAuthenticationConverter {
        val jwtAuthenticationConverter = JwtAuthenticationConverter()
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(converter)
        return jwtAuthenticationConverter
    }

    override fun configure(http: HttpSecurity) {
        http {
            cors {
                disable()
            }
            csrf {
                disable()
            }
            sessionManagement {
                sessionCreationPolicy = SessionCreationPolicy.STATELESS
            }
            authorizeRequests {
                auth.permitUrls?.forEach {
                    authorize(it, permitAll)
                }
                authorize("/clear-caches", permitAll)
                authorize("/actuator/**", permitAll)
                authorize(anyRequest)
            }
            oauth2ResourceServer {
                jwt {
                    jwtDecoder = apbJwtDecoder
                }
                bearerTokenResolver = abpBearerTokenResolver
                authenticationEntryPoint = AuthenticationEntryPoint { request, response, exception ->
                    logger.warn(
                        "Authorization failed!" +
                                "\r\nrequestURL: ${request.requestURL}" +
                                "\r\nauthorization: ${request.getHeader(HttpHeaders.AUTHORIZATION)}" +
                                "\r\nremoteAddr: ${request.remoteAddr}" +
                                "\r\nremoteHost: ${request.remoteHost}" +
                                "\r\nremotePort: ${request.remotePort}",
                        exception
                    )
                    response.status = HttpStatus.UNAUTHORIZED.value()
                    response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json")
                    response.writer.write("""{"error":{"code":401,"message":"Authorization failed! Please login and try again."}}""")
                }
                accessDeniedHandler = AccessDeniedHandler { request, response, _ ->
                    logger.warn(
                        "Permission denied!" +
                                "\r\nrequestURL: ${request.requestURL}" +
                                "\r\nauthorization: ${request.getHeader(HttpHeaders.AUTHORIZATION)}" +
                                "\r\nremoteAddr: ${request.remoteAddr}" +
                                "\r\nremoteHost: ${request.remoteHost}" +
                                "\r\nremotePort: ${request.remotePort}"
                    )
                    response.status = HttpStatus.FORBIDDEN.value()
                    response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json")
                    response.writer.write("""{"error":{"code":403,"message":"Permission denied! Given policy has not granted."}}""")
                }
            }
        }
    }

}
